package com.greenbook.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.greenbook.dto.NoteDOC;
import com.greenbook.dto.PageDTO;
import com.greenbook.mapper.NoteCategoryMapper;
import com.greenbook.mapper.NoteMapper;
import com.greenbook.mapper.NoteTagMapper;
import com.greenbook.mapper.UserInfoMapper;
import com.greenbook.service.NoteSearchService;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class NoteSearchImpl implements NoteSearchService {
    private final RestHighLevelClient client;     // 注入Elasticsearch客户端
    private final NoteMapper noteMapper;
    private final UserInfoMapper userMapper;
    private final NoteTagMapper noteTagMapper;
    private final NoteCategoryMapper noteCategoryMapper;

    /**
     * 创建es笔记索引
     */
    public void createNoteIndex() {
        // 1.检查索引是否存在
        String indexName = "note_index";
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        try {
            boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
            // 2.如果索引不存在，则创建索引
            if(!exists) {
                // 2.1 从resources加载映射文件
                ClassPathResource resource = new ClassPathResource("elasticsearch/note-mapping.json");
                String mapping;
                try(InputStream in = resource.getInputStream()) {
                    mapping = new String(in.readAllBytes(), StandardCharsets.UTF_8);
                }
                // 2.2 创建索引
                CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName)
                        .source(mapping, XContentType.JSON);
                client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 批量导入笔记数据到es
     */
    public void loadNoteDOCs() {

    }

    /**
     * 新增笔记数据到es
     */
    public void saveNoteDoc(NoteDOC noteDoc) {
        ObjectMapper objectMapper = new ObjectMapper();
        IndexRequest indexRequest = new IndexRequest("note_index").id(noteDoc.getId());
        try {
            Map<String, Object> sourceMap = objectMapper.convertValue(noteDoc, Map.class);
            indexRequest.source(sourceMap, XContentType.JSON);
            client.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 分页查询推荐笔记
     */
    @Override
    public PageDTO<NoteDOC> pageRecommend(int currentPage, int pageSize) {
        // 1.创建查询请求
        SearchRequest searchRequest = new SearchRequest("note_index");
        // 2.组织请求参数
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
                .query(QueryBuilders.matchAllQuery())
                .from((currentPage - 1) * pageSize)
                .size(pageSize);
        searchRequest.source(sourceBuilder);
        // 4.发送请求
        try {
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            // 5.解析响应
            SearchHits hits = response.getHits();
            List<NoteDOC> records = new ArrayList<>();
            if(hits.getTotalHits() != null) {
                // 5.1 获取记录数
                long total = hits.getTotalHits().value;
                // 5.2 解析分页结果
                for(SearchHit hit : hits.getHits()) {
                    // 原始结果
                    String source = hit.getSourceAsString();
                    // 转换为NoteDOC
                    NoteDOC noteDOC = new ObjectMapper().readValue(source, NoteDOC.class);
                    records.add(noteDOC);
                }
                // 6.返回结果
                return new PageDTO<>(total, (long)currentPage, records);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return new PageDTO<>();
    }
}